package cn.bijy.sqlsession;

import cn.bijy.pojo.Configuration;
import cn.bijy.pojo.MapedStatement;
import cn.bijy.pojo.SqlCommandType;

import java.lang.reflect.*;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

public class DefaultSqlSession implements SqlSession{
    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }
    private SimpleExecutor simpleExecutor = new SimpleExecutor();
    @Override
    public <E> List<E> selectList(String statementId, Object... param) throws Exception {
        MapedStatement mapedStatement = configuration.getMapedStatementMap().get(statementId);
        return simpleExecutor.query(configuration,mapedStatement,param);
    }

    public Object execute(String statementId,Type genericReturnType, Object... param) throws Exception{
        MapedStatement mapedStatement = configuration.getMapedStatementMap().get(statementId);
        SqlCommandType sqlCommandType = mapedStatement.getSqlCommandType();
        switch (sqlCommandType){
            case INSERT:
                return simpleExecutor.save(configuration,mapedStatement,param);
            case UPDATE:
                return simpleExecutor.update(configuration,mapedStatement,param);
            case SELECT:
                if (genericReturnType instanceof ParameterizedType){
                    return selectList(statementId,param);
                }
                return selectOne(statementId,param);
            default:
                throw new Exception("Unknown execution method for: " + sqlCommandType);
        }
    }

    @Override
    public <T> T selectOne(String statementId, Object... param) throws Exception {
        List<Object> objects = selectList(statementId, param);
        if (objects.size()==1){
            return (T) objects.get(0);
        }else if (objects.size()>1){
            throw new RuntimeException("返回结果过多");
        }else {
            throw new RuntimeException("返回结果错误");
        }
    }

    @Override
    public void close() throws SQLException {
        simpleExecutor.close();
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {
        Object o = Proxy.newProxyInstance(mapperClass.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();
                String key = className + "."+methodName;
                //MapedStatement mapedStatement = configuration.getMapedStatementMap().get(key);

                Type genericReturnType = method.getGenericReturnType();
//                if (genericReturnType instanceof ParameterizedType){
//                    return selectOne(key,args);
//                }

                return execute(key,genericReturnType,args);
            }
        });
        return (T) o;
    }
}
